#!/bin/sh
#
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#

# Build a qemu-bootable harddisk image.
#
# Usage:
# An optional kernel command line argument is provided with -a.
# The kernel image is provided with -k.
# The output harddisk image is specified with -o.
# Userland images are provided after that (usually only one).
#
# Authors:
# Benjamin Kalman, 2009
# Michael von Tessin, 2010

# Support build system debugging directive passed from above.
if [ 0${V} -ge 3 ]; then
    set -x
fi

# Find syslinux
SYSLINUX=`which syslinux`
if [ -z "${SYSLINUX}" ]; then
    echo "syslinux not found." >&2
    exit 1
fi
SYSLINUXDIR=`echo $SYSLINUX | sed 's:/bin/:/share/:'`
[ -d "$SYSLINUXDIR"  ] || SYSLINUXDIR="`echo $SYSLINUXDIR | sed 's:/share/:/lib/:'`"

[ -d "$SYSLINUXDIR" ] || {
       echo >&2 "Cannot find syslinux data directory!"
       exit 1
}

if [ -f "$SYSLINUXDIR"/mbr.bin ]
then
    SYSLINUX_MODULES="$SYSLINUXDIR"
    MBR="$SYSLINUXDIR"/mbr.bin
elif [ -d "$SYSLINUXDIR"/modules ]
then
    SYSLINUX_MODULES="$SYSLINUXDIR"/modules/bios/
    MBR="$SYSLINUXDIR"/mbr/mbr.bin
fi

[ -f "$MBR" ] || {
    echo >&2 "Can't find mbr.bin.  Is syslinux installed?"
    exit 1
}

trap "rm -f mtoolsrc syslinux.cfg mbr.bin" 0

# Parse options
while getopts "k:o:a:" flag ; do
    case "$flag" in
        k) KERNEL="$OPTARG" ;;
        o) OUTIMG="$OPTARG" ;;
        a) CMDLINE="$OPTARG" ;;
    esac
done
shift $(($OPTIND-1))
UIMGS=$@

if [ ! -f "$KERNEL" -o -z "$OUTIMG" -o -z "$UIMGS" ] ; then
    echo "Usage: $0 [-a kernel_cmdline] -k kernel_image -o output_image userland_images ..."
    exit 1
fi

for UIMG in $UIMGS ; do
    if [ ! -f "$UIMG" ] ; then
        echo "Error: Userland image '$UIMG' not found!"
        exit 1
    fi
done

MODULES="$SYSLINUX_MODULES/mboot.c32"
[ -f $SYSLINUX_MODULES/libcom32.c32 ] && MODULES="$MODULES $SYSLINUX_MODULES/libcom32.c32"
# Calculate image size and number of cylinders

IMGSIZE=`stat -c '%s' $UIMGS $KERNEL $MODULES | awk ' { sum += $1 } END { print sum }'`

echo "final image size will be $IMGSIZE"

HEADS=16
SECTORS=63
BLKSPERCYL=`expr $HEADS \* $SECTORS`
CYLINDERS=`expr 2 + $IMGSIZE / 512 / $BLKSPERCYL`

# Create a blank image
dd if=/dev/zero of="$OUTIMG" count=1 seek=`expr $CYLINDERS \* $BLKSPERCYL - 1` bs=512 2>/dev/null

# Set up mtools
echo "drive c: file=\"$OUTIMG\" partition=1" > mtoolsrc
export MTOOLSRC=mtoolsrc

# Get mbr.bin and blow up/cut down to 512 bytes (required by mtools)
cat "$MBR" /dev/zero 2>/dev/null | head -c 512 > mbr.bin

# Create filesystem
which mpartition >/dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "mpartition not found. Is mtools installed?" >&2
    exit 1
fi
mpartition -I -B mbr.bin c:
mpartition -c -t $CYLINDERS -h $HEADS -s $SECTORS c:
mpartition -a c:
mformat c:
syslinux --offset `expr $SECTORS \* 512` $OUTIMG

# Write syslinux config file
UIMGS_CFG=""
for UIMG in $UIMGS
do
    UIMGS_CFG="$UIMGS_CFG --- `basename $UIMG`"
done

cat > syslinux.cfg <<EOF
serial 0 115200
default mylabel

label mylabel
  kernel mboot.c32
  append `basename $KERNEL` $CMDLINE $UIMGS_CFG
EOF

# Install kernel and apps to the image
for file in $KERNEL $UIMGS $MODULES syslinux.cfg
do
    mcopy "$file" c: || {
        echo "Error: mcopy $file failed!" >&2
        exit 1
    }
done

# And we're done
echo "Image '$OUTIMG' successfully created"
